// -------------------------------------------------------------- -*- C++ -*-
// IlogViews Studio source file
//
// File: studio/src/main.cc
// --------------------------------------------------------------------------
//  Copyright (C) 1990-1996 by ILOG.
//  All Rights Reserved.
//
//  Modified by Stefan Hager , TakeFive Software, July 1996
// --------------------------------------------------------------------------


// --------------------------------------------------------------------------
// Include
// --------------------------------------------------------------------------
#include <ivstudio/studio.h>
#include <ivstudio/edappli.h>
#include <ivstudio/message.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// --------------------------------------------------------------------------
// Define & Constants
// --------------------------------------------------------------------------
#define BUFFSIZE  512

const char* toto = "toto";

// --------------------------------------------------------------------------
// Private Variable
// --------------------------------------------------------------------------
// File handle for pipe to sniffaccess
FILE *SNIFF_READ=NULL;

char BUFF[BUFFSIZE+1];

int  CONNECTED = 0;

// --------------------------------------------------------------------------
// Private Functions
// --------------------------------------------------------------------------
static void
sendCommand( char* cmd ) {
    IlvPrint( cmd );
    cout << endl << cmd << endl << flush;	
    system( cmd );
}

char * get_base_name(char * name)
{
  static char* base = 0;
  
  if (name) {
    if (name[0] == '/' && name[1] == '\0')
      base = name;
    char *cp;
    if (cp= strrchr(name, '/'))
      base = ++cp;
  }
  return base;
}    

char * get_dir_name(char * name)
{
  if (!name)
    return 0;
  if (strchr(name, '/')) {
    static char buf[BUFFSIZE+1];
    strcpy(buf, name);
    char *r= strrchr(buf, '/');
    if (r != buf)
      *r= '\0';
    if (r == buf) {
      r++;
      *r = '\0';
    }
    return buf;
  }
}	

char * get_proj_name( char * name )
{   
  FILE * handle;
  char tmpname[BUFFSIZE+1];
  static char filename[BUFFSIZE+1];
  
  char * pname = NULL;

  // build PDF name 	 
  strcpy(tmpname,name);
  strcat(tmpname,"/");
  strcat(tmpname,get_base_name( name ));
  
  strcpy(filename,tmpname);
	 
  strcat(filename,".proj");
  
  if( (handle = fopen(filename, "r")) > 0) {
    pname = filename;
    fclose( handle );
  }	 
  else
    perror("ivstudio ERROR: "); 

  if( ! pname ) {
    // no absolute project found
    strcpy(filename,tmpname);
    strcat(filename,".shared"); 	
    
    if( (handle = fopen(filename,"r")) > 0) {
      pname = filename;	
      fclose( handle );
    }
    else
      perror("ivstudio ERROR: ");	    		 		
  }
  return( pname ); 
}
 
static void 
send_notifications( char* proj, 
		    char * header, 
		    char * source, 
		    char * data)
{
  char cmd [2 * BUFFSIZE+1];
		
  sprintf( cmd, "sniffaccess add_file %s %s\n", proj, header);
  sendCommand( cmd );

  sprintf( cmd, "sniffaccess file_changed %s %s\n", proj, header);
  sendCommand( cmd );
   
  sprintf( cmd, "sniffaccess add_file %s %s\n", proj, source);
  sendCommand( cmd );
		
  sprintf( cmd, "sniffaccess file_changed %s %s\n", proj, source);
  sendCommand( cmd );
   
  sprintf( cmd, "sniffaccess add_file %s %s\n", proj, data);
  sendCommand( cmd );
	 	
  // update Makefiles	 
  sprintf( cmd, "sniffaccess update_makefiles %s 2>&1 > /dev/null\n", proj);
  sendCommand( cmd );
	
  cout << "Operation completed..." << endl << flush;	
} //send_notifications

static void 
generate_panel( IlvStApplication* appli ,
		IlvStPanelClass* pclass )
{
  if ( pclass && appli ) {
    char header[BUFFSIZE+1];
    char source[BUFFSIZE+1];  
    char data  [BUFFSIZE+1];
    char cmd   [BUFFSIZE+1];
  
    char * dir = NULL;
    char * pname =  NULL;
    char * pbname;

    // SNiFF+ running ?
    if( !CONNECTED ) return;
    
    cout << " Class :" << pclass->getName() << endl;
    
    // Determine filenames and current project name
    strcpy(header, appli->getHeaderFile(pclass));
    strcpy(source, appli->getSourceFile(pclass));	
    strcpy(data,   appli->getDataFile(pclass));	
      
    dir = get_dir_name(source);
    pname = get_proj_name(dir);
    pbname = get_base_name(pname);

    sprintf( cmd, "cd %s\n",dir);
    sendCommand( cmd );
		    
    // if project exists : send notifications to SNiFF+
    if( pbname ) { 
      send_notifications(pbname,
			 get_base_name(source),
			 get_base_name(header),
			 get_base_name(data));
    }
    else 
      cout << "No projects found in " << dir << endl << flush;
    
    cout.flush();
  }
} //generate_panel

// --------------------------------------------------------------------------
// Callback Functions
// --------------------------------------------------------------------------
static void ILVCALLBACK 
ApplicationGenerated ( IlvAny,
		       IlvStudio* editor,
		       const IlvStMessage*,
		       IlvAny)
{   
    char header[BUFFSIZE+1];
    char source[BUFFSIZE+1];  
    char data  [BUFFSIZE+1];
    char cmd   [BUFFSIZE+1];
		
    char * dir = NULL;
    char * pname =  NULL;
    char * pbname;
	 
    // SNiFF+ running ?    
    if( ! CONNECTED ) return;
    
    IlvStApplication* appli = editor->getApplication();

    // Determine filenames and current project name
    strcpy(header,appli->getHeaderFile());
    strcpy(source,appli->getSourceFile());	
    strcpy(data,appli->getDataFile());	

    dir = get_dir_name(source);	
    pname = get_proj_name(dir);	
    pbname = get_base_name(pname);
	    
    sprintf( cmd, "cd %s\n",dir);
    sendCommand( cmd );
		    
    // if project exists : send notifications to SNiFF+     
    if( pbname ) {
      send_notifications(pbname,get_base_name(source),
			 get_base_name(header),get_base_name(data));
    }	
    else 
      cout << "No projects found in " << dir << endl << flush;
   
} // ApplicationGenerated

// --------------------------------------------------------------------------
static void ILVCALLBACK 
PanelClassGenerated(IlvAny,
		    IlvStudio* editor,
		    const IlvStMessage*,
		    IlvAny)
{
    IlvStApplication * appli = editor->getApplication();
    if (!appli) return;
    IlvStPanelClass* pclass = appli->getPanelClass();
    if (!pclass) return;

    generate_panel( appli , pclass );

} // PanelClassGenerated

// --------------------------------------------------------------------------
static void ILVCALLBACK 
ApplicationClassesGenerated(IlvAny arg1,
			    IlvStudio* editor,
			    const IlvStMessage* arg2,
			    IlvAny arg3)
{
  ApplicationGenerated( arg1 , editor , arg2 , arg3 );

  IlvStApplication* appli = editor->getApplication();	
  if (!appli ) return ;

  IlvStPanelClass* pclass;
  const IlvArray& pclasses = appli->getPanelClasses();
  
  for (IlvUInt ndx = 0; ndx < pclasses.getLength(); ndx++) {
    generate_panel( appli , (IlvStPanelClass*)pclasses[ndx] );
  }
} // ApplicationClassesGenerated

// --------------------------------------------------------------------------
// Main Function
// --------------------------------------------------------------------------
// ===========================================================================

// --------------------------------------------------------------------------
static void
InitializeMyStudio(IlvStudio* editor)
{
  // GenerateApplication
  editor->messages().subscribe("GenerateApplication",
			       new IlvStMessageCallback((IlvAny)toto, 
							ApplicationGenerated));

  // Generate a Panel
  editor->messages().subscribe("GeneratePanelClass",
			       new IlvStMessageCallback((IlvAny)toto, 
							PanelClassGenerated));

  // Generate All
  editor->messages().subscribe("ClassesGenerated",
			       new IlvStMessageCallback((IlvAny)toto, 
							ApplicationClassesGenerated));
}

// --------------------------------------------------------------------------
extern "C" IlvBoolean IlvSetLanguage();
// extern "C" unsigned long IlvSetCurrentCharSet(unsigned long);

// ------------------------------------------------------------------
main(int argc, char* argv[])
{
  int len=0;
  // IlvSetCurrentCharSet(<YourCharSet>);
  IlvSetLanguage(); // set locale according to environment variables (unix)
  // --- Display ---
  IlvDisplay* display = new IlvDisplay("ivstudio", "", argc, argv);
  if (display->isBad()) {
    IlvFatalError("Couldn't open display");
    delete display;
    return -1;
  }

  // --- Path ---
  const char* ilvhome = display->getHome();
  if (ilvhome && *ilvhome) {
    const char* addir = "studio/data/";
    const char* icdir = "gif/";
    char* path =
      new char [strlen(ilvhome) + strlen(addir) + strlen(icdir) + 1];
    strcpy(path, ilvhome);
    strcat(path, addir);
    display->appendToPath(path);
    strcat(path, icdir);
    display->appendToPath(path);
  } else
    display->appendToPath("../data");
  if (display->findInPath("paninsp.ilv") == NULL) {
    IlvFatalError("paninsp.ilv not found in ILVPATH. Check your ILVHOME environment variable.");
    delete display;
    return 0;
  }

  // --- create pipe for connection to sniffaccess ---  
  SNIFF_READ = popen("echo exit \\n | sniffaccess 2>&1","r");
 
  // --- open pipe to sniffaccess and check for a running SNiFF+ ---
  while (!feof(SNIFF_READ)) {
    fgets(BUFF,BUFFSIZE,SNIFF_READ);
    if( strncmp(BUFF,"sniffaccess: connected",22) == 0)
      break; 
  }
  if (feof(SNIFF_READ)) {
    pclose(SNIFF_READ);
    SNIFF_READ = NULL;
    cout << "SNiFF+ is not running or connection failed.." << endl 
	 << flush; 
  }

  if( SNIFF_READ != NULL) {   
    cout << "sniffaccess connected.." << endl << flush;
    
    // --- check wether SNiFF+ is connected ---    
    fgets(BUFF,BUFFSIZE,SNIFF_READ);

    if(strncmp(BUFF,"sniffaccess:",12) != 0) {  
      pclose(SNIFF_READ);
      cout << "SNiFF+ is not connected to sniffappcomm.." << endl
	   << flush;
    }
    else {  
      cout << "SNiFF+ running and connected.." << endl << flush;   
      pclose(SNIFF_READ);
      SNIFF_READ = NULL;
      CONNECTED = 1;
    }
  }
  // --- Let's go ---
  IlvStudio* editor = new IlvStudio(display);
  editor->initialize();
  InitializeMyStudio(editor);
  IlvMainLoop();
  return 0;
}

